<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>重新布局不改变视窗</title>
</head>
<body>
  <button id='changeView'>改变布局</button>
<div id="mountNode"></div>
<script src="../build/g6.js"></script>
<script src="../build//grid.js"></script>
<script>

  G6.registerBehavior('click-add-node', {
    getEvents() {
      return {
        'node:click': 'onClick'
      };
    },
    onClick(ev) {
      const itemModel = ev.item.getModel();
      clickedNodeId = itemModel.id;
      const graph = this.graph;
      const nodes = graph.getNodes();
      const edges = graph.getEdges();
      let newData;
      if (itemModel.id == 2) {
        newData = data2_m;
      } else {
        return;
      }
      
      let newNodeModels = newData.nodes;
      let newEdgeModels = [];
      // deduplication the items in newEdgeModels
      newData.edges.forEach(e => {
        let exist = false;
        newEdgeModels.forEach(ne => {
          if(ne.source === e.source && ne.target === e.target) exist = true;
        });
        if(!exist) {
          newEdgeModels.push(e);
        }
      });

      // for graph.changeData()
      const allNodeModels = [];
      const allEdgeModels = [];
      
      // add new nodes to graph
      const nodeMap = new Map();
      nodes.forEach((n, i)=>{
        const nModel = n.getModel();
        nodeMap.set(nModel.id, i);
      });
      
      newNodeModels.forEach((nodeModel, i) => {
        if (nodeMap.get(nodeModel.id) === undefined) {
          // set the initial positions of the new nodes to the focus(clicked) node
          nodeModel.x = itemModel.x;
          nodeModel.y = itemModel.y;
          const node = graph.addItem('node', nodeModel);
        }
      });

      // add new edges to graph
      const edgeMap = new Map();
      edges.forEach((e, i)=>{
        const eModel = e.getModel();
        edgeMap.set(eModel.source+","+eModel.target, i);
      });

      const oldEdgeNum = edges.length;
      newEdgeModels.forEach((em, i) => {
        const exist = edgeMap.get(em.source+","+em.target);
        if (exist === undefined) {
          const edge = graph.addItem('edge', em);
          edgeMap.set(em.source+","+em.target, oldEdgeNum+i);
        }
      });

      edges.forEach((e, i) => {
        allEdgeModels.push(e.getModel());
      });

      nodes.forEach((n, i) => {
        allNodeModels.push(n.getModel());
      });
      // the max degree about foces(clicked) node in the newly added data
      const maxDegree = 4;
      // the max degree about foces(clicked) node in the original data
      const oMaxDegree = 3;
      const unitRadius = 40;
      const focusNodeId = "2";
      // re-place the clicked node far away the exisiting items
      // along the radius from center node to it
      const vx = itemModel.x - focusNode.x;
      const vy = itemModel.y - focusNode.y;
      const vlength = Math.sqrt(vx*vx+vy*vy);
      const ideallength = unitRadius * maxDegree + mainUnitRadius * oMaxDegree;
      itemModel.x = ideallength * vx / vlength + focusNode.x;
      itemModel.y = ideallength * vy / vlength + focusNode.y;

      const subRadialLayout = new Radial({
        center: [ itemModel.x, itemModel.y ],
        maxIteration: 200,
        focusNode: "2",
        unitRadius,
        linkDistance: 180
      }); 
      graph.addPlugin(subRadialLayout);
      // only layout the newly added part around the clicked node
      subRadialLayout.layout( 
        {
          'nodes': newNodeModels,
          'edges': newEdgeModels
        }
      );
      graph.changeData({"nodes": allNodeModels, "edges": allEdgeModels});
    }
  });




  const grid = new Grid()
  const graph = new G6.TreeGraph({
    plugins: [grid],
    container: 'mountNode',
    width: 500,
    height: 500,
    defaultNode: {
      size: [20, 20]
    },
    modes: {
      default: [ 'drag-node', 'drag-canvas', {
        type: 'collapse-expand',
        onChange(item, collapsed) {
          const data = item.getModel()
          data.collapsed = collapsed
          return true
        }
      } ]
    },
    nodeStyle: {
      default: {
        fill: '#40a9ff',
  			stroke: '#096dd9'
      }
    },
  	edgeStyle: {
    	default: {
      	stroke: '#A3B1BF'
    	}
  	},
  	defaultEdge: {
    	shape: 'cubic-horizontal'
    },
    layout: {
      type: 'dendrogram',
      nodeSep: 50,
      rankSep: 100,
      direction: 'LR'
    }
  });

  let data = {
    isRoot: true,
    id: 'Root',
  	style: {
      fill: 'red'
    },
    children: [
      {
        id: 'SubTreeNode1',
        raw: {},
        children: [
          {
            id: 'SubTreeNode1.1'
          }
        ]
      },
      {
        id: 'SubTreeNode2',
        children: [
          {
            id: 'SubTreeNode2.1'
          },
          {
            id: 'SubTreeNode2.2'
          }
        ]
      } 
    ]
  };

  graph.data(data)
  graph.render()

  graph.fitView()

  document.getElementById('changeView').addEventListener('click', (evt) => {
    const matrix = G6.Util.clone(graph.get('group').getMatrix())
    data.children.pop()
    graph.changeData(data)
    graph.get('group').setMatrix(matrix)
    graph.paint()
  })
  
</script>
</body>
</html>
